<?php

namespace App\Traits;

use App\Exceptions\BusinessException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

// 验证前端传参是否合法的代码块
trait VerifyFrontEndParameters
{
    /**
     * 为什么要这个代码块？因为现在只要发请求的地方涉及到参数验证都是如下这样写的
     *  $rule = [
     *      "id" => "required|integer"
     *  ]
     *  $input = $request->input()
     *  $validateRet = Validator::make($input, $rule);
     * if ($validateRet->fails()) {
     * return result(1, $validateRet->errors()->first());
     * }
     *  看这段代码以及结合每个方法，会发现除了验证规则不同以外，从 $input 那一行到验证完成的代码都是一样的；
     *  同样，在不同的业务方法里，验证的字段的规则可能也会相同，比如上面案例里的 id，它会在其它的业务方法里同样存在。
     *  分析发现，如果按照这样写，那会产生大量重复代码。所以将它剥离出来封装成一个 trait。
     *
     *  我们就还是用上面的代码案例进行一步一步的分析，分解和封装。
     *  1. 代码案例里验证的是，前端要传入 id 这个名称的字段，required 表示必须的，integer 表示必须是整型；
     *  那可以理解为 id 是一个 key，这个 key 就是一个变量，后面的 required、integer...是验证规则，规则是 laravel 内置提供不变的；
     *  因此只要是验证一个字段【必传，整型】，那就可以用这套规则，只是它的 key 不一定叫 id，有的业务方法里叫 user_id、post_id 等等。
     *  所以可以起一个方法，专门验证这类 id 用的。
     *  2. 将 $input 开始到结束的这段代码提炼封装成一个函数。
     *
     *  verifyId 函数只是一个很简单的验证函数，只能验证叫 "id" 这一类的字段。
     *  如果碰到一个【业务参数很多】的业务方法，每一个参数调一个验证方法，如果有20个参数，那就要调20个验证函数，这样显然是不行的；
     *  对于这种业务参数很多的，可以封装成一个类。就拿这个项目里的发布招工这个业务来讲解：
     *  1. 发布招工这个业务需要十几个参数，将其封装成一个类，每一个参数当作类的一个属性；
     *  2. 再编写一个验证规则的函数，里面是每个参数的验证规则。
     */

    public function verifyId($verifyKey, $defaultVerifyKeyValue = null)
    {
        return $this->verifyData($verifyKey, 'required|integer');
    }

    public function verifySting($verifyKey)
    {
        return $this->verifyData($verifyKey, 'required|string');
    }

    public function verifyData($verifyKey, $rule)
    {
        // 获取需要验证的 key，这种方式获取到的可能不是一个数组
        $verifyKeyValue = request()->input($verifyKey);

        // 因为 Validator::make，make 方法需要的两个参数必须是数组，所以这里要组装成数组。
        $verifyData = [$verifyKey => $verifyKeyValue];
        $verifyRule = [$verifyKey => $rule];

        // 进行验证
        $this->check($verifyData, $verifyRule);

        return $verifyKeyValue;
    }

    /**
     * 为什么封装一个 check 方法，因为这样更灵活，当业务参数很多的时候，如果用 request()->input($verifyKey) 这种方式获取太麻烦了。
     * 在前台可以直接使用 request()->input() 方法获取所有参数直接调用这个 check 方法。
     * @param array $verifyData
     * @param array $verifyRule
     * @throws BusinessException
     */
    public function check($verifyData, $verifyRule)
    {
        $validateRet = Validator::make($verifyData, $verifyRule);
        if ($validateRet->fails()) {
            throw new BusinessException($validateRet->errors()->first(), 1);
        }
    }

}
